#include <clock.h>
#include <defs.h>
#include <sbi.h>
#include <stdio.h>
#include <riscv.h>

//编译器不要对这个变量瞎优化
volatile size_t ticks;


//bne循环的目的是确保在读取高位和低位时间之间没有发生时间溢出。
//确保读取到的高位和低位时间是在同一个时间周期中获取的，
//保证获取到的64位时间戳是连续和准确的。

//通过使用位移和位运算，将32位的高位时间hi左移32位，
//并与低位时间lo进行按位或操作，得到一个64位的时间戳，将其作为函数的返回值。
static inline uint64_t get_cycles(void) {
#if __riscv_xlen == 64
    uint64_t n;
    __asm__ __volatile__("rdtime %0" : "=r"(n));
    return n;
#else
    uint32_t lo, hi, tmp;
    __asm__ __volatile__(
        "1:\n"
        "rdtimeh %0\n"
        "rdtime %1\n"
        "rdtimeh %2\n"
        "bne %0, %2, 1b"
        : "=&r"(hi), "=&r"(lo), "=&r"(tmp));
    return ((uint64_t)hi << 32) | lo;
#endif
}


// Hardcode 硬编码 timebase
static uint64_t timebase = 100000;

/* *
 * clock_init - initialize 8253 clock to interrupt 100 times per second,
 * and then enable IRQ_TIMER.
 * 8253是一个具有定时器和计数器功能的芯片，常用于计时和时钟相关的操作。
 * 每秒触发100次中断
 * 初始化的过程包括设置8253时钟的工作模式和计数器的值，
 * 使其以适当的频率生成中断信号，并启用IRQ_TIMER中断。
 * */
void clock_init(void) {
    // sie这个CSR可以单独使能/禁用某个来源的中断。默认时钟中断是关闭的
    // enable timer interrupt in sie
    //在 sie 寄存器中启用计时器中断（STIP，Supervisor Timer Interrupt Pending）。
    //这将允许处理器在计时器到达设定的下一个事件时触发中断。
    set_csr(sie, MIP_STIP);
    // divided by 500 除500 when using Spike(2MHz)
    // divided by 100 除100 when using QEMU(10MHz)
    // timebase = sbi_timebase() / 500;
    clock_set_next_event();
    //会设置下一个时钟事件的触发时间。
    // initialize time counter 'ticks' to zero
    ticks = 0;
    //记录时钟中断的次数或时间计数器的值。

    cprintf("++ setup timer interrupts\n");
}

void clock_set_next_event(void) { sbi_set_timer(get_cycles() + timebase); }
//sbi_set_timer被调用，并将当前时间（通过get_cycles()获取）
//加上 timebase 的值作为参数传递给 sbi_set_timer 函数。
//表示下一个时钟事件将在当前时间加上 timebase 的时间后触发。

//设置时钟中断：timer的数值变为当前时间 + timebase 后，触发一次时钟中断
//对于QEMU, timer增加1，过去了10^-7 s， 也就是100ns